package library.http;

import android.support.annotation.NonNull;
import android.text.TextUtils;

import java.io.File;
import java.lang.reflect.Type;
import java.net.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import library.http.ssl.SslConfig;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;

/**
 * Created by Mr.Fan on 2017/1/8.
 */

public class HttpTask {
    private boolean debuggable;
    private String tag;

    private Proxy proxy;
    private List<KeyValue<String, String[]>> certificatePinner = new ArrayList<>();

    private String baseUrl;
    private String url;
    private HttpMethod method;

    private long timeoutConnect;
    private long timeoutWrite;
    private long timeoutRead;

    private boolean formUrlEncoded;
    private boolean multipart;
    private String multiType = "multipart/form-data";

    private Map<String, Object> headers;
    private Map<String, Object> params;

    private Map<String, Object> queries;
    private Map<String, FormField> fields;
    private Map<String, Object> parts;

    private Download<?> download;

    private String cache;
    private SslConfig sslConfig;
    private OkHttpClient httpClient;
    private List<Converter> converterList = new ArrayList<>();
    private Class returnClass = null;
    private Type returnType = null;

    protected HttpTask() {
    }

    public HttpTask tag(Object tag) {
        this.tag = HttpManager.key(tag);
        return this;
    }

    public String getTag() {
        return this.tag;
    }

    public HttpTask debuggable(boolean b) {
        this.debuggable = b;
        return this;
    }

    public HttpTask baseUrl(@NonNull String baseUrl) {
        this.baseUrl = baseUrl;
        return this;
    }

    public HttpTask timeout(long connect, long write, long read) {
        this.timeoutConnect = connect;
        this.timeoutWrite = write;
        this.timeoutRead = read;
        return this;
    }

    public HttpTask url(String url) {
        this.url = url;
        return this;
    }

    public HttpTask cache(String cache) {
        this.cache = cache;
        return this;
    }

    public HttpTask proxy(String host) {
        return proxy(host, 80);
    }

    public HttpTask proxy(String host, int port) {
        return proxy(HttpUtils.getProxy(host, port));
    }

    public HttpTask proxy(Proxy proxy) {
        this.proxy = proxy;
        return this;
    }

    public HttpTask certificatePinner(String pattern, String... pins) {
        if (!TextUtils.isEmpty(pattern) && pins != null)
            certificatePinner.add(new KeyValue<>(pattern, pins));
        return this;
    }

    protected HttpTask certificatePinner(List<KeyValue<String, String[]>> list) {
        if (list != null)
            this.certificatePinner.addAll(list);
        return this;
    }

    public HttpTask method(HttpMethod method) {
        this.method = method;
        return this;
    }

    public HttpTask method(String method) {
        if (TextUtils.isEmpty(method)) {
            this.method = null;
        } else {
            try {
                this.method = HttpMethod.valueOf(method.trim().toUpperCase());
            } catch (Exception e) {

            }
        }
        return this;
    }

    public HttpTask get() {
        this.method = HttpMethod.GET;
        return this;
    }

    public HttpTask post() {
        this.method = HttpMethod.POST;
        return this;
    }

    public HttpTask put() {
        this.method = HttpMethod.PUT;
        return this;
    }

    public HttpTask patch() {
        this.method = HttpMethod.PATCH;
        return this;
    }

    public HttpTask head() {
        this.method = HttpMethod.HEAD;
        return this;
    }

    public HttpTask delete() {
        this.method = HttpMethod.DELETE;
        return this;
    }

    public HttpTask formUrlEncoded() {
        this.multipart = false;
        this.formUrlEncoded = true;
        return this;
    }

    public HttpTask multipart() {
        return multipart(null);
    }

    public HttpTask multipart(String multiType) {
        if (!TextUtils.isEmpty(multiType))
            this.multiType = multiType;
        this.multipart = true;
        this.formUrlEncoded = false;
        return this;
    }

    public synchronized HttpTask header(@NonNull String key, Object value) {
        if (!TextUtils.isEmpty(key) && value != null) {
            if (headers == null)
                headers = new HashMap<>();
            headers.put(key, value);
        }
        return this;
    }

    public synchronized HttpTask headers(Map<String, Object> map) {
        if (map != null) {
            if (headers == null)
                headers = new HashMap<>();
            headers.putAll(map);
        }
        return this;
    }

    public synchronized HttpTask params(Map<String, Object> map) {
        if (map != null) {
            if (params == null)
                params = new HashMap<>();
            params.putAll(map);
        }
        return this;
    }

    public synchronized HttpTask param(@NonNull String key, Object value) {
        if (!TextUtils.isEmpty(key) && value != null) {
            if (params == null)
                params = new HashMap<>();
            params.put(key, value != null ? String.valueOf(value) : null);
        }
        return this;
    }

    public HttpTask field(@NonNull String key, Object value) {
        return field(key, value, false);
    }

    public synchronized HttpTask field(@NonNull String key, Object value, boolean encoded) {
        if (!TextUtils.isEmpty(key) && value != null) {
            if (fields == null)
                fields = new HashMap<>();
            fields.put(key, new FormField(String.valueOf(value), encoded));
        }
        return this;
    }

    public synchronized HttpTask field(Map<String, FormField> fields) {
        if (fields != null) {
            if (fields == null)
                fields = new HashMap<>();
            fields.putAll(fields);
        }
        return this;
    }

    public synchronized HttpTask query(@NonNull String key, Object value) {
        if (!TextUtils.isEmpty(key)) {
            if (queries == null)
                queries = new HashMap<>();
            queries.put(key, value);
        }
        return this;
    }

    public synchronized HttpTask query(Map<String, Object> queries) {
        if (queries != null) {
            if (queries == null)
                queries = new HashMap<>();
            queries.putAll(queries);
        }
        return this;
    }

    public synchronized HttpTask part(@NonNull String key, Object value) {
        if (!TextUtils.isEmpty(key) && value != null) {
            if (parts == null)
                parts = new HashMap<>();
            parts.put(key, value);
        }
        return this;
    }

    public synchronized HttpTask part(@NonNull String key, File value) {
        if (!TextUtils.isEmpty(key) && value != null) {
            if (parts == null)
                parts = new HashMap<>();
            parts.put(key, value);
        }
        return this;
    }

    public synchronized HttpTask part(@NonNull String key, FilePart<?> value) {
        if (!TextUtils.isEmpty(key) && value != null) {
            if (parts == null)
                parts = new HashMap<>();
            parts.put(key, value);
        }
        return this;
    }

    public HttpTask download(Download<?> download) {
        this.download = download;
        return this;
    }

    public HttpTask converter(Converter converter) {
        if (converter != null)
            this.converterList.add(converter);
        return this;
    }

    public HttpTask converter(List<Converter> list) {
        if (list != null)
            this.converterList.addAll(list);
        return this;
    }

    protected HttpTask returnClass(Class returnClass) {
        this.returnClass = returnClass;
        return this;
    }

    protected HttpTask returnType(Type returnType) {
        this.returnType = returnType;
        return this;
    }

    public HttpTask client(OkHttpClient client) {
        this.httpClient = client;
        return this;
    }

    public HttpTask ssl(SslConfig sslConfig) {
        this.sslConfig = sslConfig;
        return this;
    }

    /************************************
     * callback
     *********************************************************/

    public Request request() {
        return new HttpHandler(this).request();
    }

    public Call call() {
        return new HttpHandler(this).call();
    }

    public <T> T execute() throws Exception {
        return new HttpHandler(this).execute();
    }

    public <T> T execute(Class<T> genericReturnType) throws Exception {
        return new HttpHandler(this).execute(genericReturnType);
    }

    public <T> void callback(HttpCallback<T> httpCallback) {
        new HttpHandler(this).callback(httpCallback);
    }


    /************************************
     * get
     **********************************************************/

    protected String getBaseUrl() {
        return baseUrl;
    }

    public String getUrl() {
        return url;
    }

    protected Proxy getProxy() {
        return proxy;
    }

    protected List<KeyValue<String, String[]>> getCertificatePinner() {
        return certificatePinner;
    }

    protected HttpMethod getMethod() {
        return method;
    }

    protected long getTimeoutConnect() {
        return timeoutConnect;
    }

    protected long getTimeoutWrite() {
        return timeoutWrite;
    }

    protected long getTimeoutRead() {
        return timeoutRead;
    }

    protected boolean isFormUrlEncoded() {
        return formUrlEncoded;
    }

    protected boolean isMultipart() {
        return multipart;
    }

    protected String getMultiType() {
        return multiType;
    }

    protected Map<String, Object> getHeaders() {
        return headers;
    }

    protected Map<String, Object> getParams() {
        return params;
    }

    protected Map<String, Object> getQueries() {
        return queries;
    }

    protected Map<String, FormField> getFields() {
        return fields;
    }

    protected Map<String, Object> getParts() {
        return parts;
    }

    protected Download<?> getDownload() {
        return download;
    }

    protected OkHttpClient getHttpClient() {
        return httpClient;
    }

    protected SslConfig getSslConfig() {
        return sslConfig;
    }

    protected String getCache() {
        return cache;
    }

    protected List<Converter> getConverterList() {
        return converterList;
    }


    protected Type getReturnType() {
        return returnType;
    }

    protected Class getReturnClass() {
        return returnClass;
    }

    protected boolean isDebuggable() {
        return debuggable;
    }

}
